﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;

namespace Qas.CommonLogic.BusinessObjects.Probability
{
    /// <summary>
    /// Вероятностное распределение - набор пар "Результат - Количество эксприментов"
    /// Класс описывает моделируемую ситуацию, оцениваемую по одному параметру. Была проведена 
    /// серия экспериментов, а результаты сохранены.
    /// </summary>
    public class ProbabilityDistribution
    {
        #region для Сериализации

        private Pair[] pairsArray;

        internal Pair[] PairsArray
        {
            get
            {
                return this.pairsArray;
            }
            set
            {
                this.pairsArray = value;
            }
        }

        /// <summary>
        /// Конструктор для десериализации
        /// </summary>
        public ProbabilityDistribution()
        {
            // Пишем в лог о десериализации объекта
            LogicalLog.Write(LogicalLog.deserialization_message + this.GetType().Name);
        }

        #endregion

        /// <summary>
        /// Сумма всех результатов
        /// </summary>
        private double valueSumm = 0;

        /// <summary>
        /// Количество реализованных экспериментов
        /// </summary>
        private int experimentsCount = 0;

        /// <summary>
        /// Список пар в рамках данной модели
        /// </summary>
        private List<Pair> pairs = new List<Pair>();

        ///// <summary>
        ///// Конструктор для работы в рамках системы
        ///// </summary>
        ///// <param name="pairs">Список пар, по которым строится объект</param>
        //public ProbabilityDistribution(List<Pair> pairs)
        //{
        //    if (pairs != null)
        //    {
        //        this.pairs = pairs;
        //    }
        //}

        /// <summary>
        /// Конструктор, создающий экземпляр класса на основе массива пар (Pair)
        /// </summary>
        /// <param name="pairs">Массив пар, по которым строится объект</param>
        public ProbabilityDistribution(Pair[] pairs)
        {
            for (int i = 0; i < pairs.Length; i++)
            {
                this.pairs.Add(pairs[i]);

            }
        }

        /// <summary>
        /// Математическое ожидание результата эксперимента
        /// </summary>
        public double Expectancy
        {
            get
            {
                // Проверяем, вычислялось ли ранее это значение
                if (this.experimentsCount == 0)
                {
                    // Считаем средневзвешенное значение
                    
                    foreach (Pair pair in this.pairs)
                    {
                        this.valueSumm += pair.Count * pair.Value;
                        this.experimentsCount += pair.Count;
                    }
                }
                
                // Находим отношение
                double result = this.valueSumm / this.experimentsCount;
                
                // Округляем
                return Math.Round(result, 2);
            }
        }

        /// <summary>
        /// Добавление в список результата нового эксперимента
        /// </summary>
        /// <param name="result">Добавляемый результат эксперимента</param>
        public void AddResult(double result)
        {
            // Проверяем, был ли уже получен такой результат
            foreach (Pair pair in this.pairs)
            {
                if (pair.Value == result)
                {
                    // Если такой результат уже достигался, 
                    // увеличиваем на 1 количество экспериментов
                    pair.Count += 1;

                    // Корректируем значения переменных, 
                    // определяющих математическое ожидание
                    this.experimentsCount++;
                    this.valueSumm += result;

                    // И сваливаем отсюда
                    return;
                }
            }

            // Если все пары кончились, а мы ещё в этом 
            // методе, значит такого резульата пока не было
            Pair newPair = new Pair(result);

            // Приобщаем к благому делу накопления статистики
            this.pairs.Add(newPair);

            // Обновляем сериализуемый массив пар
            this.PairsArray = this.pairs.ToArray();
        }

        public override string ToString()
        {
            return this.Expectancy.ToString();
        }
    }
}
